{{>partial_header}}

use reqwest;

use crate::apis::ResponseContent;
use super::{Error, configuration};

{{#operations}}
{{#operation}}
{{#vendorExtensions.x-group-parameters}}
{{#allParams}}
{{#-first}}
/// struct for passing parameters to the method [`{{operationId}}`]
#[derive(Clone, Debug, Default)]
pub struct {{{operationIdCamelCase}}}Params {
{{/-first}}
    {{#description}}
    /// {{{.}}}
    {{/description}}
    pub {{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{#isArray}}Vec<{{/isArray}}String{{#isArray}}>{{/isArray}}{{/isString}}{{#isUuid}}{{#isArray}}Vec<{{/isArray}}String{{#isArray}}>{{/isArray}}{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}{{#isBodyParam}}crate::models::{{/isBodyParam}}{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}},{{/-last}}
{{#-last}}
}

{{/-last}}
{{/allParams}}
{{/vendorExtensions.x-group-parameters}}
{{/operation}}
{{/operations}}

{{#supportMultipleResponses}}
{{#operations}}
{{#operation}}
/// struct for typed successes of method [`{{operationId}}`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum {{{operationIdCamelCase}}}Success {
    {{#responses}}
    {{#is2xx}}
    Status{{code}}({{#isEnum}}{{{enumName}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}),
    {{/is2xx}}
    {{#is3xx}}
    Status{{code}}({{#isEnum}}{{{enumName}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}),
    {{/is3xx}}
    {{/responses}}
    UnknownValue(serde_json::Value),
}

{{/operation}}
{{/operations}}
{{/supportMultipleResponses}}
{{#operations}}
{{#operation}}
/// struct for typed errors of method [`{{operationId}}`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum {{{operationIdCamelCase}}}Error {
    {{#responses}}
    {{#is4xx}}
    Status{{code}}({{#isEnum}}{{{enumName}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}),
    {{/is4xx}}
    {{#is5xx}}
    Status{{code}}({{#isEnum}}{{{enumName}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}),
    {{/is5xx}}
    {{#isDefault}}
    DefaultResponse({{#isEnum}}{{{enumName}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}),
    {{/isDefault}}
    {{/responses}}
    UnknownValue(serde_json::Value),
}

{{/operation}}
{{/operations}}

{{#operations}}
{{#operation}}
{{#description}}
/// {{{.}}}
{{/description}}
{{#notes}}
/// {{{.}}}
{{/notes}}
{{#vendorExtensions.x-group-parameters}}
pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration: &configuration::Configuration{{#allParams}}{{#-first}}, params: {{{operationIdCamelCase}}}Params{{/-first}}{{/allParams}}) -> Result<{{#supportMultipleResponses}}ResponseContent<{{{operationIdCamelCase}}}Success>{{/supportMultipleResponses}}{{^supportMultipleResponses}}{{^returnType}}(){{/returnType}}{{{returnType}}}{{/supportMultipleResponses}}, Error<{{{operationIdCamelCase}}}Error>> {
    let local_var_configuration = configuration;

    // unbox the parameters
    {{#allParams}}
    let {{paramName}} = params.{{paramName}};
    {{/allParams}}

{{/vendorExtensions.x-group-parameters}}
{{^vendorExtensions.x-group-parameters}}
pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration: &configuration::Configuration, {{#allParams}}{{{paramName}}}: {{^required}}Option<{{/required}}{{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{#isString}}{{#isArray}}Vec<{{/isArray}}{{^isUuid}}&str{{/isUuid}}{{#isArray}}>{{/isArray}}{{/isString}}{{#isUuid}}{{#isArray}}Vec<{{/isArray}}&str{{#isArray}}>{{/isArray}}{{/isUuid}}{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}{{#isBodyParam}}crate::models::{{/isBodyParam}}{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}{{^required}}>{{/required}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) -> Result<{{#supportMultipleResponses}}ResponseContent<{{{operationIdCamelCase}}}Success>{{/supportMultipleResponses}}{{^supportMultipleResponses}}{{^returnType}}(){{/returnType}}{{{returnType}}}{{/supportMultipleResponses}}, Error<{{{operationIdCamelCase}}}Error>> {
    let local_var_configuration = configuration;
{{/vendorExtensions.x-group-parameters}}

    let local_var_client = &local_var_configuration.client;

    let local_var_uri_str = format!("{}{{{path}}}", local_var_configuration.base_path{{#pathParams}}, {{{baseName}}}={{#isString}}crate::apis::urlencode({{/isString}}{{{paramName}}}{{^required}}.unwrap(){{/required}}{{#required}}{{#isNullable}}.unwrap(){{/isNullable}}{{/required}}{{#isArray}}.join(",").as_ref(){{/isArray}}{{#isString}}){{/isString}}{{/pathParams}});
    let mut local_var_req_builder = local_var_client.request(reqwest::Method::{{{httpMethod}}}, local_var_uri_str.as_str());

    {{#queryParams}}
    {{#required}}
    local_var_req_builder = local_var_req_builder.query(&[("{{{baseName}}}", &{{{paramName}}}{{#isArray}}.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(","){{/isArray}}.to_string())]);
    {{/required}}
    {{^required}}
    if let Some(ref local_var_str) = {{{paramName}}} {
        local_var_req_builder = local_var_req_builder.query(&[("{{{baseName}}}", &local_var_str{{#isArray}}.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(","){{/isArray}}.to_string())]);
    }
    {{/required}}
    {{/queryParams}}
    {{#hasAuthMethods}}
    {{#authMethods}}
    {{#isApiKey}}
    {{#isKeyInQuery}}
    if let Some(ref local_var_apikey) = local_var_configuration.api_key {
        let local_var_key = local_var_apikey.key.clone();
        let local_var_value = match local_var_apikey.prefix {
            Some(ref local_var_prefix) => format!("{} {}", local_var_prefix, local_var_key),
            None => local_var_key,
        };
        local_var_req_builder = local_var_req_builder.query(&[("{{{keyParamName}}}", local_var_value)]);
    }
    {{/isKeyInQuery}}
    {{/isApiKey}}
    {{/authMethods}}
    {{/hasAuthMethods}}
    if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
        local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
    }
    {{#hasHeaderParams}}
    {{#headerParams}}
    {{#required}}
    {{^isNullable}}
    local_var_req_builder = local_var_req_builder.header("{{{baseName}}}", {{{paramName}}}{{#isArray}}.join(","){{/isArray}}.to_string());
    {{/isNullable}}
    {{#isNullable}}
    match {{{paramName}}} {
        Some(local_var_param_value) => { local_var_req_builder = local_var_req_builder.header("{{{baseName}}}", local_var_param_value{{#isArray}}.join(","){{/isArray}}.to_string()); },
        None => { local_var_req_builder = local_var_req_builder.header("{{{baseName}}}", ""); },
    }
    {{/isNullable}}
    {{/required}}
    {{^required}}
    if let Some(local_var_param_value) = {{{paramName}}} {
        local_var_req_builder = local_var_req_builder.header("{{{baseName}}}", local_var_param_value{{#isArray}}.join(","){{/isArray}}.to_string());
    }
    {{/required}}
    {{/headerParams}}
    {{/hasHeaderParams}}
    {{#hasAuthMethods}}
    {{#authMethods}}
    {{#isApiKey}}
    {{#isKeyInHeader}}
    if let Some(ref local_var_apikey) = local_var_configuration.api_key {
        let local_var_key = local_var_apikey.key.clone();
        let local_var_value = match local_var_apikey.prefix {
            Some(ref local_var_prefix) => format!("{} {}", local_var_prefix, local_var_key),
            None => local_var_key,
        };
        local_var_req_builder = local_var_req_builder.header("{{{keyParamName}}}", local_var_value);
    };
    {{/isKeyInHeader}}
    {{/isApiKey}}
    {{#isBasic}}
    {{#isBasicBasic}}
    if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth {
        local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned());
    };
    {{/isBasicBasic}}
    {{#isBasicBearer}}
    if let Some(ref local_var_token) = local_var_configuration.bearer_access_token {
        local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned());
    };
    {{/isBasicBearer}}
    {{/isBasic}}
    {{#isOAuth}}
    if let Some(ref local_var_token) = local_var_configuration.oauth_access_token {
        local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned());
    };
    {{/isOAuth}}
    {{/authMethods}}
    {{/hasAuthMethods}}
    {{#isMultipart}}
    {{#hasFormParams}}
    let mut local_var_form = reqwest::multipart::Form::new();
    {{#formParams}}
    {{#isFile}}
    {{^supportAsync}}
    {{#required}}
    {{^isNullable}}
    local_var_form = local_var_form.file("{{{baseName}}}", {{{paramName}}})?;
    {{/isNullable}}
    {{#isNullable}}
    match {{{paramName}}} {
        Some(local_var_param_value) => { local_var_form = local_var_form.file("{{{baseName}}}", local_var_param_value)?; },
        None => { unimplemented!("Required nullable form file param not supported"); },
    }
    {{/isNullable}}
    {{/required}}
    {{^required}}
    if let Some(local_var_param_value) = {{{paramName}}} {
        local_var_form = local_var_form.file("{{{baseName}}}", local_var_param_value)?;
    }
    {{/required}}
    {{/supportAsync}}
    {{#supportAsync}}
    // TODO: support file upload for '{{{baseName}}}' parameter
    {{/supportAsync}}
    {{/isFile}}
    {{^isFile}}
    {{#required}}
    {{^isNullable}}
    local_var_form = local_var_form.text("{{{baseName}}}", {{{paramName}}}{{#isArray}}.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(","){{/isArray}}.to_string());
    {{/isNullable}}
    {{#isNullable}}
    match {{{paramName}}} {
        Some(local_var_param_value) => { local_var_form = local_var_form.text("{{{baseName}}}", local_var_param_value{{#isArray}}.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(","){{/isArray}}.to_string()); },
        None => { local_var_form = local_var_form.text("{{{baseName}}}", ""); },
    }
    {{/isNullable}}
    {{/required}}
    {{^required}}
    if let Some(local_var_param_value) = {{{paramName}}} {
        local_var_form = local_var_form.text("{{{baseName}}}", local_var_param_value{{#isArray}}.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(","){{/isArray}}.to_string());
    }
    {{/required}}
    {{/isFile}}
    {{/formParams}}
    local_var_req_builder = local_var_req_builder.multipart(local_var_form);
    {{/hasFormParams}}
    {{/isMultipart}}
    {{^isMultipart}}
    {{#hasFormParams}}
    let mut local_var_form_params = std::collections::HashMap::new();
    {{#formParams}}
    {{#isFile}}
    {{#required}}
    {{^isNullable}}
    local_var_form_params.insert("{{{baseName}}}", unimplemented!("File form param not supported with x-www-form-urlencoded content"));
    {{/isNullable}}
    {{#isNullable}}
    match {{{paramName}}} {
        Some(local_var_param_value) => { local_var_form_params.insert("{{{baseName}}}", unimplemented!("File form param not supported with x-www-form-urlencoded content")); },
        None => { unimplemented!("Required nullable file form param not supported with x-www-form-urlencoded content"); },
    }
    {{/isNullable}}
    {{/required}}
    {{^required}}
    if let Some(local_var_param_value) = {{{paramName}}} {
        local_var_form_params.insert("{{{baseName}}}", unimplemented!("File form param not supported with x-www-form-urlencoded content"));
    }
    {{/required}}
    {{/isFile}}
    {{^isFile}}
    {{#required}}
    {{^isNullable}}
    local_var_form_params.insert("{{{baseName}}}", {{{paramName}}}{{#isArray}}.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(","){{/isArray}}.to_string());
    {{/isNullable}}
    {{#isNullable}}
    match {{{paramName}}} {
        Some(local_var_param_value) => { local_var_form_params.insert("{{{baseName}}}", local_var_param_value{{#isArray}}.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(","){{/isArray}}.to_string()); },
        None => { local_var_form_params.insert("{{{baseName}}}", ""); },
    }
    {{/isNullable}}
    {{/required}}
    {{^required}}
    if let Some(local_var_param_value) = {{{paramName}}} {
        local_var_form_params.insert("{{{baseName}}}", local_var_param_value{{#isArray}}.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(","){{/isArray}}.to_string());
    }
    {{/required}}
    {{/isFile}}
    {{/formParams}}
    local_var_req_builder = local_var_req_builder.form(&local_var_form_params);
    {{/hasFormParams}}
    {{/isMultipart}}
    {{#hasBodyParam}}
    {{#bodyParams}}
    local_var_req_builder = local_var_req_builder.json(&{{{paramName}}});
    {{/bodyParams}}
    {{/hasBodyParam}}

    let local_var_req = local_var_req_builder.build()?;
    let {{^supportAsync}}mut {{/supportAsync}}local_var_resp = local_var_client.execute(local_var_req){{#supportAsync}}.await{{/supportAsync}}?;

    let local_var_status = local_var_resp.status();
    let local_var_content = local_var_resp.text(){{#supportAsync}}.await{{/supportAsync}}?;

    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
        {{^supportMultipleResponses}}
        {{^returnType}}
        Ok(())
        {{/returnType}}
        {{#returnType}}
        serde_json::from_str(&local_var_content).map_err(Error::from)
        {{/returnType}}
        {{/supportMultipleResponses}}
        {{#supportMultipleResponses}}
        let local_var_entity: Option<{{{operationIdCamelCase}}}Success> = serde_json::from_str(&local_var_content).ok();
        let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
        Ok(local_var_result)
        {{/supportMultipleResponses}}
    } else {
        let local_var_entity: Option<{{{operationIdCamelCase}}}Error> = serde_json::from_str(&local_var_content).ok();
        let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
        Err(Error::ResponseError(local_var_error))
    }
}

{{/operation}}
{{/operations}}
